#!/usr/bin/env python3
import argparse
import socket
import ipaddress
import subprocess
import threading
import netifaces
import sys

parser = argparse.ArgumentParser(description='ip ping tool')
parser.add_argument('-i', '--ip', type=str, dest='ip', help='ip/mask')
args = parser.parse_args()

ip_list = []
ip_list_lock = threading.Lock()

def get_os():
    if sys.platform.startswith('win'):
        return 'windows'
    elif sys.platform.startswith('linux'):
        return 'linux'
    elif sys.platform.startswith('darwin'):
        return 'macos'
    else:
        print('UnknownOsType:',sys.platform)
        return 'Unknown'

os_type = get_os()
if os_type == 'win':
    command_ping = ['ping', '-n', '1', '-w', '5000', '<host>'] # Windows
elif os_type == 'macos':
    command_ping = ['ping', '-c', '1', '-W', '5', '<host>'] # linux
elif os_type == 'linux':
    command_ping = ['ping', '-c', '1', '-t', '5', '<host>'] # Mac
else:
    exit(1)

def is_host_alive(host):
    command_ping_temp = command_ping[:-1]
    command_ping_temp.append(host)
    try:
        subprocess.run(command_ping_temp, capture_output=True, shell=False, check=True, timeout=5) # param:check will called error when code is not zero
    except subprocess.TimeoutExpired:
        # print('[Timeout]',host)
        return False
    except subprocess.CalledProcessError:
        # print('[CallErr]',host)
        return False
    return True

def get_gateway_address():
    gateways = netifaces.gateways()
    default_gateway = gateways.get("default", {})
    ipv4_gateway = default_gateway.get(netifaces.AF_INET)
    if ipv4_gateway:
        print('Gateway:',ipv4_gateway)
        return ipv4_gateway[0]

def get_local_network_ip():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.connect(("8.8.8.8", 80))
    local_ip = udp_socket.getsockname()[0]
    udp_socket.close()
    return local_ip

def get_local_network_segment(local_ip):
    network_segment = ".".join(local_ip.split(".")[:-1]) + ".0/24"
    return network_segment

def ping_device(ip):
    if is_host_alive(ip):
        print('[Active ]', ip)
        ip_list_lock.acquire()
        ip_list.append(ip)
        ip_list_lock.release()
    else:
        pass

def scan_local_network(network_segment):
    threads = []
    for ip in ipaddress.IPv4Network(network_segment):
        ip = str(ip)
        thread = threading.Thread(target=ping_device, args=(ip,))
        threads.append(thread)
        thread.start()

    for thread in threads:
        thread.join()

if __name__ == "__main__":
    local_ip = get_local_network_ip()
    print("LocalIp:", local_ip)
    if args.ip:
        ip_address = args.ip
    else:
        ip_address = get_gateway_address()
    network_segment = get_local_network_segment(ip_address)
    print("NetMask:", network_segment)
    scan_local_network(network_segment)
    print("ActiveIpList:",ip_list)
